package org.merak.core.persistence.jdbc;

import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;

public class XPreparedStatement implements PreparedStatement {

	//~ Attributes /////////////////////////////////////////////////////////////
	//**************************************************************************
	private XConnection       conn = null;
	private PreparedStatement pstm = null;
	private String            sql  = null;

	//~ Constructors ///////////////////////////////////////////////////////////
	//**************************************************************************
	public XPreparedStatement(XConnection connection,String sql) throws SQLException {
		this.conn = connection;
		this.sql  = sql;
	}
	//~ Methods ////////////////////////////////////////////////////////////////
	//**************************************************************************
	protected void renew() throws SQLException  {

		this.pstm = this.conn.getWrappedConnection().prepareStatement(this.sql);

	}
	//**************************************************************************
	protected PreparedStatement getStatement() throws SQLException {
		if (this.conn.isClosed() || this.pstm==null) this.renew();
		return this.pstm;
	}
	//**************************************************************************
	@Override
	public void addBatch() throws SQLException {
		this.getStatement().addBatch();
	}
	//**************************************************************************
	@Override
	public void clearParameters() throws SQLException {
		this.getStatement().clearParameters();
	}
	//**************************************************************************
	@Override
	public boolean execute() throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().execute();
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().execute();
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public ResultSet executeQuery() throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeQuery();
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<ResultSet>() {
				@Override
				public ResultSet retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeQuery();
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate() throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeUpdate();
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeUpdate();
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public ResultSetMetaData getMetaData() throws SQLException {
		return this.getStatement().getMetaData();
	}
	//**************************************************************************
	@Override
	public ParameterMetaData getParameterMetaData() throws SQLException {
		return this.getStatement().getParameterMetaData();
	}
	//**************************************************************************
	@Override
	public void setArray(int arg0, Array arg1) throws SQLException {
		this.getStatement().setArray(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setAsciiStream(int arg0, InputStream arg1) throws SQLException {
		this.getStatement().setAsciiStream(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setAsciiStream(int arg0, InputStream arg1, int arg2)
			throws SQLException {
		this.getStatement().setAsciiStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setAsciiStream(int arg0, InputStream arg1, long arg2)
			throws SQLException {
		this.getStatement().setAsciiStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setBigDecimal(int arg0, BigDecimal arg1) throws SQLException {
		this.getStatement().setBigDecimal(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBinaryStream(int arg0, InputStream arg1) throws SQLException {
		this.getStatement().setBinaryStream(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBinaryStream(int arg0, InputStream arg1, int arg2)
			throws SQLException {
		this.getStatement().setBinaryStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setBinaryStream(int arg0, InputStream arg1, long arg2)
			throws SQLException {
		this.getStatement().setBinaryStream(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBlob(int arg0, Blob arg1) throws SQLException {
		this.getStatement().setBlob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBlob(int arg0, InputStream arg1) throws SQLException {
		this.getStatement().setBlob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBlob(int arg0, InputStream arg1, long arg2)
			throws SQLException {
		this.getStatement().setBlob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBoolean(int arg0, boolean arg1) throws SQLException {
		this.getStatement().setBoolean(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setByte(int arg0, byte arg1) throws SQLException {
		this.getStatement().setByte(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setBytes(int arg0, byte[] arg1) throws SQLException {
		this.getStatement().setBytes(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setCharacterStream(int arg0, Reader arg1) throws SQLException {
		this.getStatement().setCharacterStream(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setCharacterStream(int arg0, Reader arg1, int arg2)
			throws SQLException {
		this.getStatement().setCharacterStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setCharacterStream(int arg0, Reader arg1, long arg2)
			throws SQLException {
		this.getStatement().setCharacterStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setClob(int arg0, Clob arg1) throws SQLException {
		this.getStatement().setClob(arg0, arg1);

	}
	//**************************************************************************
	@Override
	public void setClob(int arg0, Reader arg1) throws SQLException {
		this.getStatement().setClob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setClob(int arg0, Reader arg1, long arg2) throws SQLException {
		this.getStatement().setClob(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setDate(int arg0, Date arg1) throws SQLException {
		this.getStatement().setDate(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setDate(int arg0, Date arg1, Calendar arg2) throws SQLException {
		this.getStatement().setDate(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setDouble(int arg0, double arg1) throws SQLException {
		this.getStatement().setDouble(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setFloat(int arg0, float arg1) throws SQLException {
		this.getStatement().setFloat(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setInt(int arg0, int arg1) throws SQLException {
		this.getStatement().setInt(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setLong(int arg0, long arg1) throws SQLException {
		this.getStatement().setLong(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNCharacterStream(int arg0, Reader arg1) throws SQLException {
		this.getStatement().setNCharacterStream(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNCharacterStream(int arg0, Reader arg1, long arg2)
			throws SQLException {
		this.getStatement().setNCharacterStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setNClob(int arg0, NClob arg1) throws SQLException {
		this.getStatement().setNClob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNClob(int arg0, Reader arg1) throws SQLException {
		this.getStatement().setNClob(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNClob(int arg0, Reader arg1, long arg2) throws SQLException {
		this.getStatement().setNClob(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setNString(int arg0, String arg1) throws SQLException {
		this.getStatement().setNString(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNull(int arg0, int arg1) throws SQLException {
		this.getStatement().setNull(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setNull(int arg0, int arg1, String arg2) throws SQLException {
		this.getStatement().setNull(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setObject(int arg0, Object arg1) throws SQLException {
		this.getStatement().setObject(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setObject(int arg0, Object arg1, int arg2) throws SQLException {
		this.getStatement().setObject(arg0, arg1,arg2);
	}
	//**************************************************************************
	@Override
	public void setObject(int arg0, Object arg1, int arg2, int arg3)
			throws SQLException {
		this.getStatement().setObject(arg0, arg1, arg2, arg3);
	}
	//**************************************************************************
	@Override
	public void setRef(int arg0, Ref arg1) throws SQLException {
		this.getStatement().setRef(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setRowId(int arg0, RowId arg1) throws SQLException {
		this.getStatement().setRowId(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setSQLXML(int arg0, SQLXML arg1) throws SQLException {
		this.getStatement().setSQLXML(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setShort(int arg0, short arg1) throws SQLException {
		this.getStatement().setShort(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setString(int arg0, String arg1) throws SQLException {
		this.getStatement().setString(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setTime(int arg0, Time arg1) throws SQLException {
		this.getStatement().setTime(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setTime(int arg0, Time arg1, Calendar arg2) throws SQLException {
		this.getStatement().setTime(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setTimestamp(int arg0, Timestamp arg1) throws SQLException {
		this.getStatement().setTimestamp(arg0, arg1);
	}
	//**************************************************************************
	@Override
	public void setTimestamp(int arg0, Timestamp arg1, Calendar arg2) throws SQLException {
		this.getStatement().setTimestamp(arg0, arg1, arg2);
	}
	//**************************************************************************
	@Override
	public void setURL(int arg0, URL arg1) throws SQLException {
		this.getStatement().setURL(arg0, arg1);
	}
	//**************************************************************************
	@Override
	@Deprecated
	public void setUnicodeStream(int arg0, InputStream arg1, int arg2)
			throws SQLException {

		this.getStatement().setUnicodeStream(arg0, arg1, arg2);
	}
	//**************************************************************************
	//**************************************************************************
	@Override
	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		return this.getStatement().isWrapperFor(arg0);
	}
	//**************************************************************************
	@Override
	public <T> T unwrap(Class<T> arg0) throws SQLException {
		return this.getStatement().unwrap(arg0);
	}
	//**************************************************************************
	@Override
	public void addBatch(String arg0) throws SQLException {
		this.getStatement().addBatch(arg0);
	}
	//**************************************************************************
	@Override
	public void cancel() throws SQLException {
		this.getStatement().cancel();
	}
	//**************************************************************************
	@Override
	public void clearBatch() throws SQLException {
		this.getStatement().clearBatch();
	}
	//**************************************************************************
	@Override
	public void clearWarnings() throws SQLException {
		this.getStatement().clearWarnings();
	}
	//**************************************************************************
	@Override
	public void close() throws SQLException {
		this.getStatement().close();
	}
	//**************************************************************************
	@Override
	public boolean execute(final String sql) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().execute(sql);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().execute(sql);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0, final int arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0, final int[] arg1) throws SQLException {

		try {
			// Try to execute normally
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public boolean execute(final String arg0,final String[] arg1) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().execute(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Boolean>() {
				@Override
				public Boolean retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().execute(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int[] executeBatch() throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeBatch();
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<int[]>() {
				@Override
				public int[] retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeBatch();
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public ResultSet executeQuery(final String sql) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeQuery(sql);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<ResultSet>() {
				@Override
				public ResultSet retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeQuery(sql);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final int arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0,arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeUpdate(arg0,arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final int[] arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeUpdate(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0,final String[] arg1)
		throws SQLException
	{
		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0, arg1);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeUpdate(arg0, arg1);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public int executeUpdate(final String arg0) throws SQLException {

		// Try to execute normally
		try {
			return this.getStatement().executeUpdate(arg0);
		}
		// Retry if closed connection or throw the exception
		catch (SQLException e) {
			return new SQLExecutor<Integer>() {
				@Override
				public Integer retryOnClosedConnetion() throws SQLException {
					return XPreparedStatement.this.getStatement().executeUpdate(arg0);
				}
			}.execute(this.conn, e);
		}

	}
	//**************************************************************************
	@Override
	public XConnection getConnection() throws SQLException {
		return this.conn;
	}
	//**************************************************************************
	@Override
	public int getFetchDirection() throws SQLException {
		return this.getStatement().getFetchDirection();
	}
	//**************************************************************************
	@Override
	public int getFetchSize() throws SQLException {
		return this.getStatement().getFetchSize();
	}
	//**************************************************************************
	@Override
	public ResultSet getGeneratedKeys() throws SQLException {
		return this.getStatement().getGeneratedKeys();
	}
	//**************************************************************************
	@Override
	public int getMaxFieldSize() throws SQLException {
		return this.getStatement().getMaxFieldSize();
	}
	//**************************************************************************
	@Override
	public int getMaxRows() throws SQLException {
		return this.getStatement().getMaxRows();
	}
	//**************************************************************************
	@Override
	public boolean getMoreResults() throws SQLException {
		return this.getStatement().getMoreResults();
	}
	//**************************************************************************
	@Override
	public boolean getMoreResults(int arg0) throws SQLException {
		return this.getStatement().getMoreResults(arg0);
	}
	//**************************************************************************
	@Override
	public int getQueryTimeout() throws SQLException {
		return this.getStatement().getQueryTimeout();
	}
	//**************************************************************************
	@Override
	public ResultSet getResultSet() throws SQLException {
		return this.getStatement().getResultSet();
	}
	//**************************************************************************
	@Override
	public int getResultSetConcurrency() throws SQLException {
		return this.getStatement().getResultSetConcurrency();
	}
	//**************************************************************************
	@Override
	public int getResultSetHoldability() throws SQLException {
		return this.getStatement().getResultSetHoldability();
	}
	//**************************************************************************
	@Override
	public int getResultSetType() throws SQLException {
		return this.getStatement().getResultSetType();
	}
	//**************************************************************************
	@Override
	public int getUpdateCount() throws SQLException {
		return this.getStatement().getUpdateCount();
	}
	//**************************************************************************
	@Override
	public SQLWarning getWarnings() throws SQLException {
		return this.getStatement().getWarnings();
	}
	//**************************************************************************
	@Override
	public boolean isClosed() throws SQLException {
		return this.getStatement().isClosed();
	}
	//**************************************************************************
	@Override
	public boolean isPoolable() throws SQLException {
		return this.getStatement().isPoolable();
	}
	//**************************************************************************
	@Override
	public void setCursorName(String arg0) throws SQLException {
		this.getStatement().setCursorName(arg0);
	}
	//**************************************************************************
	@Override
	public void setEscapeProcessing(boolean arg0) throws SQLException {
		this.getStatement().setEscapeProcessing(arg0);
	}
	//**************************************************************************
	@Override
	public void setFetchDirection(int arg0) throws SQLException {
		this.getStatement().setFetchDirection(arg0);
	}
	//**************************************************************************
	@Override
	public void setFetchSize(int arg0) throws SQLException {
		this.getStatement().setFetchSize(arg0);

	}
	//**************************************************************************
	@Override
	public void setMaxFieldSize(int arg0) throws SQLException {
		this.getStatement().setMaxFieldSize(arg0);
	}
	//**************************************************************************
	@Override
	public void setMaxRows(int arg0) throws SQLException {
		this.getStatement().setMaxRows(arg0);
	}
	//**************************************************************************
	@Override
	public void setPoolable(boolean arg0) throws SQLException {
		this.getStatement().setPoolable(arg0);
	}
	//**************************************************************************
	@Override
	public void setQueryTimeout(int arg0) throws SQLException {
		this.getStatement().setQueryTimeout(arg0);
	}
	//**************************************************************************

}
